﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FinanSoft.Entities;
using FinanSoft.Utilities;
using System.Collections;
using FinanSoft.DataLayer;

namespace FinanSoft.BusinessLayer
{
    public class AuxiliaryAccountManager
    {

        #region Atributos
        /// <summary>
        /// Única instancia de esta clase
        /// </summary>
        private static AuxiliaryAccountManager _instance;
        private Hashtable _AuxiliaryAccounts;
        private List<String> _PayConditionsList;
        private bool _IsError;
        private String _ErrorMessage;
        #endregion

        #region Constructor singleton
        private AuxiliaryAccountManager()
        {
            _IsError = false;
            _ErrorMessage = "";
            // Aqui tengo que llamar a la función para leer la lista de cuentas
            _AuxiliaryAccounts = AuxAccountDataManager.GetInstance().GetAuxiliarAccountsList();
            _PayConditionsList = AuxAccountDataManager.GetInstance().GetPayConditionsList();
            if (_AuxiliaryAccounts == null)
            {
                _IsError = true;
                _ErrorMessage = Constants.ERROR_GET_AUXILIAR_ACCOUNTS;
            }
            if (_PayConditionsList == null)
            {
                _IsError = true;
                _ErrorMessage = Constants.ERROR_GET_PAY_COND_LIST;
            }
            else
            {
                _IsError = false;
            }
        }         
        
        /// <summary>
        /// Método para implementar el patrón de Singleton
        /// </summary>
        /// <returns>Instancia única de la clase</returns>
        public static AuxiliaryAccountManager GetInstance()
        {
            if (_instance == null)
                _instance = new AuxiliaryAccountManager();
            return _instance;
        }
        #endregion

        #region Propiedades
        public bool IsError
        {
            get
            {
                bool temp = _IsError;
                _IsError = false;
                return temp;
            }
        }

        public String ErrorMessage
        {
            get
            {
                String temp = _ErrorMessage;
                _IsError = false;
                _ErrorMessage = "";
                return temp;
            }
        }
        #endregion

        #region Métodos públicos de clase
        /// <summary>
        /// Método que se encarga de crear una nueva cuenta auxiliar, y asignarle una
        /// cuenta mayor con el id de cuenta padre que se recibe
        /// </summary>
        /// <param name="account">Cuenta a agregar</param>
        /// <param name="fatherID">id de la cuenta mayor</param>
        /// <returns>Retorna booleano de éxito o no</returns>
        public bool CreateNewAuxiliarAccount(AuxiliarAccount account)
        {
            // Se revisa que la cuenta a agregar no tenga el mismo código que las ya agregadas
            // en el catálogo contable
            if (GetAuxiliarAccount(account.AccountCode) != null)
            {
                _IsError = true;
                _ErrorMessage = Constants.ERROR_ACCOUNT_CODE_FAILED;
                return false;
            }
            // Se agrega la cuenta a la base de datos y se revisa si no hubo algún error
            int noErrorDB = AuxAccountDataManager.GetInstance().CreateNewAuxiliarAccount(account);
            if (noErrorDB == -1)
            {
                _IsError = true;
                _ErrorMessage = Constants.ERROR_NEW_ACCOUNT_FAILED;
                return false;
            }
            account.AccountID = noErrorDB;
            _AuxiliaryAccounts.Add(noErrorDB, account);
            return true;
        }

        /// <summary>
        /// Método que se encarga de crear una condición de pago
        /// </summary>
        /// <param name="condName">nombre de la condición</param>
        /// <returns>retorna si hubo éxito en la operación o no</returns>
        public bool CreatePayCondition(String condName, int days)
        {
            if (!_PayConditionsList.Contains(condName))
            {
                // Se crea la condición en la base de datos y se revisa que no haya error, 
                bool noErrorDB = AuxAccountDataManager.GetInstance().CreatePayCondition(condName, days);
                if (!noErrorDB)
                {
                    _IsError = true;
                    _ErrorMessage = Constants.ERROR_NEW_PAY_COND;
                    return false;
                }
                _PayConditionsList.Add(condName);
                return true;
            }
            else
            {
                _IsError = true;
                _ErrorMessage = Constants.ERROR_PAY_COND_EXISTS;
                return false;
            }
        }

        /// <summary>
        /// Método que se encarga de eliminar una cuenta auxiliar
        /// </summary>
        /// <param name="accountID">id de la cuenta a eliminar</param>
        /// <returns>Retorna el booleano de éxito o no</returns>
        public bool DeleteAuxiliarAccount(int accountID)
        {
            // Se elimina la cuenta en la base de datos y se revisa que no haya error, 
            // de ser así se deshacen los cambios...
            bool noErrorDB = AuxAccountDataManager.GetInstance().DeleteAuxiliarAccount(accountID);
            if (!noErrorDB)
            {
                _IsError = true;
                _ErrorMessage = Constants.ERROR_NEW_ACCOUNT_FAILED;
                return false;
            }
            _AuxiliaryAccounts.Remove(accountID);
            return true;
        }

        /// <summary>
        /// Método que se encarga de eliminar una condición de pago
        /// </summary>
        /// <param name="condName">nombre de la condición</param>
        /// <returns>retorna si hubo éxito en la operación o no</returns>
        public bool DeletePayCondition(String condName)
        {
            // Se elimina la cuenta en la base de datos y se revisa que no haya error, 
            // de ser así se deshacen los cambios...
            bool noErrorDB = AuxAccountDataManager.GetInstance().DeletePayCondition(condName);
            if (!noErrorDB)
            {
                _IsError = true;
                _ErrorMessage = Constants.ERROR_DELETE_PAY_COND;
                return false;
            }
            _PayConditionsList.Remove(condName);
            return true;
        }

        /// <summary>
        /// Método que se encarga de modidicar la cuenta auxiliar especificada
        /// </summary>
        /// <param name="account">cuenta a modificar</param>
        /// <returns>Retorna booleano de éxito o no</returns>
        public bool ModifyAuxiliarAccount(AuxiliarAccount account)
        {
            // Se modifica la cuenta en la base de datos y se revisa que no haya habido errores
            // y si los hubo modifica la cuenta a la original
            bool noError = AuxAccountDataManager.GetInstance().ModifyAuxiliarAccount(account);
            if (!noError)
            {
                _IsError = true;
                _ErrorMessage = Constants.ERROR_EDIT_ACCOUNT_FAILED;
                return false;
            }
            AuxiliarAccount oldAccount =  (AuxiliarAccount)_AuxiliaryAccounts[account.AccountID];
            account.Amount = account.Amount * oldAccount.AccountCurrency.ToLocalCurrency / account.AccountCurrency.ToLocalCurrency;
            _AuxiliaryAccounts.Remove(account.AccountID);
            _AuxiliaryAccounts.Add(account.AccountID, account);
            return true;
        }

        /// <summary>
        /// Método que se encarga de devolver una lista de cuentas auxiliares
        /// </summary>
        /// <returns>Retorna una lista con todas la cuentas</returns>
        public Hashtable GetAuxiliarAccountsList()
        {
            if (_AuxiliaryAccounts == null)
            {
                _IsError = true;
                _ErrorMessage = Constants.ERROR_GET_AUXILIAR_ACCOUNTS;
            }
            return _AuxiliaryAccounts;
        }

        /// <summary>
        /// Método que se encarga de devolver una lista de condiciones de pago
        /// </summary>
        /// <returns>Retorna una lista con todas los nombres de las condiciones de pago</returns>
        public List<String> GetConditionsList()
        {
            if (_PayConditionsList == null)
            {
                _IsError = true;
                _ErrorMessage = Constants.ERROR_GET_PAY_COND_LIST;
            }
            return _PayConditionsList;
        }

        /// <summary>
        /// Método que se encarga de devolver una lista de cuentas auxiliares segun tipo solicitados
        /// </summary>
        /// <returns>Retorna un arreglo con la cuentas</returns>
        public AuxiliarAccount[] GetAuxiliarAccountsListByType(int idTipoCtaAux)
        {
            _IsError = false;
            _ErrorMessage = "";
            // Aqui tengo que llamar a la función para leer la lista de cuentas
            AuxiliarAccount[]  _AuxiliaryAccountByType = AuxAccountDataManager.GetInstance().GetAuxiliarAccountsListByType(idTipoCtaAux);
            if (_AuxiliaryAccountByType == null)
            {
                _IsError = true;
                _ErrorMessage = Constants.ERROR_GET_AUXILIAR_ACCOUNTS;
            }
            else
            {
                _IsError = false;
            }
            return _AuxiliaryAccountByType;
        }

        /// <summary>
        /// Busca una cuenta con el Id dado en la lista de cuentas
        /// Si no existe entonces devuelve nulo
        /// </summary>
        /// <param name="id">Id de la cuenta que se busca</param>
        /// <returns>Cuenta asociada al Id, nulo si no existe</returns>
        public AuxiliarAccount GetAuxiliarAccount(int id)
        {
            if (_AuxiliaryAccounts.Contains(id))
                return (AuxiliarAccount)_AuxiliaryAccounts[id];
            return null;
        }

        /// <summary>
        /// Busca una cuenta con el codigo dado en el catálogo de cuentas
        /// Si no existe entonces devuelve nulo
        /// </summary>
        /// <param name="id">codigo de la cuenta que se busca</param>
        /// <returns>Cuenta asociada al codigo, nulo si no existe</returns>
        public AuxiliarAccount GetAuxiliarAccount(String code)
        {
            foreach (AuxiliarAccount account in _AuxiliaryAccounts.Values)
            {
                if (account.AccountCode == code)
                    return account;
            }
            return null;
        }
        #endregion

    }
}
